/*
 * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
 * Copyright 2016-2019 NXP
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY NXP "AS IS" AND ANY EXPRESSED OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL NXP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

/*!
 * @file flexcan_driver.c
 *
 * @page misra_violations MISRA-C:2012 violations
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 15.5, Return statement before end of function.
 * The return statement before end of function is used for simpler code structure
 * and better readability.
 *
 * @section [global]
 * Violates MISRA 2012 Required Rule 1.3, Taking address of near auto variable
 * The code is not dynamically linked. An absolute stack address is obtained when
 * taking the address of the near auto variable. A source of error in writing
 * dynamic code is that the stack segment may be different from the data segment.
 *
 * @section [global]
 * Violates MISRA 2012 Required Rule 11.6, cast from unsigned char to pointer
 * The cast is needed for a function which has a generic parameter of type void*.
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 11.4, conversion between a pointer and integer
 * type.
 * The cast is needed to obtain an address for a DMA call.
 *
 * @section [global]
 * Violates MISRA 2012 Required Rule 11.6, cast from pointer to unsigned long
 * The cast is needed to obtain an address for a DMA call.
 *
 * @section [global]
 * Violates MISRA 2012 Required Rule 2.2, Highest operation, function
 * 'FLEXCAN_UnlockRxMsgBuff', lacks side-effects.
 * The function is used to unlock the mailbox, which is done by reading the
 * free running timer.
 *
 * @section [global]
 * Violates MISRA 2012 Advisory Rule 8.7, External could be made static.
 * Function is defined for usage by application code.
 *
 * @section [global]
 * Violates MISRA 2012 Required Rule 11.3, cast performed between a pointer to
 * object type and a pointer to a different object type
 * The cast is used for casting a bytes buffer into an words buffer in order to
 * optimize copying data to/from the message buffer.
 */

#include "flexcan_hw_access.h"
#include "flexcan_irq.h"
#include "interrupt_manager.h"
#include "clock_manager.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define FLEXCAN_MB_HANDLE_RXFIFO    0U

/* CAN bit timing values */
#define FLEXCAN_NUM_TQ_MIN     8U
#define FLEXCAN_NUM_TQ_MAX    26U
#define FLEXCAN_PRESDIV_MAX  256U
#define FLEXCAN_PSEG1_MAX      8U
#define FLEXCAN_PSEG2_MIN      1U
#define FLEXCAN_PSEG2_MAX      8U
#define FLEXCAN_PROPSEG_MAX    8U
#define FLEXCAN_TSEG1_MIN      2U
#define FLEXCAN_TSEG1_MAX     17U
#define FLEXCAN_TSEG2_MIN      2U
#define FLEXCAN_TSEG2_MAX      9U
#define FLEXCAN_RJW_MAX        3U

/*******************************************************************************
 * Variables
 ******************************************************************************/

/* Table of base addresses for CAN instances. */
static CAN_Type * const g_flexcanBase[] = CAN_BASE_PTRS;

/* Tables to save CAN IRQ enum numbers defined in CMSIS header file. */
#if FEATURE_CAN_HAS_WAKE_UP_IRQ
static const IRQn_Type g_flexcanWakeUpIrqId[] = CAN_Wake_Up_IRQS;
#endif
static const IRQn_Type g_flexcanErrorIrqId[] = CAN_Error_IRQS;
static const IRQn_Type g_flexcanBusOffIrqId[] = CAN_Bus_Off_IRQS;
static const IRQn_Type g_flexcanOredMessageBufferIrqId[FEATURE_CAN_MB_IRQS_MAX_COUNT][CAN_INSTANCE_COUNT] =
		FEATURE_CAN_MB_IRQS;

/* Pointer to runtime state structure.*/
static flexcan_state_t * g_flexcanStatePtr[CAN_INSTANCE_COUNT] = { NULL };

/*******************************************************************************
 * Private Functions
 ******************************************************************************/
static status_t FLEXCAN_StartSendData(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id,
		const uint8_t *mb_data,
		bool isBlocking);
static status_t FLEXCAN_StartRxMessageBufferData(uint8_t instance,
		uint8_t mb_idx, flexcan_msgbuff_t *data,
		bool isBlocking);
static status_t FLEXCAN_StartRxMessageFifoData(uint8_t instance,
		flexcan_msgbuff_t *data,
		bool isBlocking);
static void FLEXCAN_CompleteTransfer(uint8_t instance, uint32_t mb_idx);
static void FLEXCAN_CompleteRxMessageFifoData(uint8_t instance);
#if FEATURE_CAN_HAS_DMA_ENABLE
static void FLEXCAN_CompleteRxFifoDataDMA(void *parameter,
		edma_chn_status_t status);
#endif
static void FLEXCAN_BitrateToTimeSeg(uint32_t bitrate, uint32_t clkFreq,
		flexcan_time_segment_t *timeSeg);
static inline void FLEXCAN_IRQHandlerRxFIFO(uint8_t instance, uint32_t mb_idx);
static inline void FLEXCAN_IRQHandlerRxMB(uint8_t instance, uint32_t mb_idx);
static inline void FLEXCAN_EnableIRQs(uint8_t instance);
#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
static inline void FLEXCAN_Errata10368(uint8_t instance,
		const flexcan_user_config_t *data);
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */
/*******************************************************************************
 * Code
 ******************************************************************************/

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetBitrate
 * Description   : Set FlexCAN baudrate.
 * This function will set up all the time segment values for classical frames or the
 * extended time segments for the arbitration phase of FD frames. Those time segment
 * values are passed in by the user and are based on the required baudrate.
 *
 * Implements    : FLEXCAN_DRV_SetBitrate_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetBitrate(uint8_t instance,
		const flexcan_time_segment_t *bitrate) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(bitrate != NULL);

	CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FD
	bool fdEnabled = FLEXCAN_IsFDEnabled(base);
#endif

	FLEXCAN_EnterFreezeMode(base);

#if FEATURE_CAN_HAS_FD
	if (fdEnabled) {
		/* Set extended time segments*/
		FLEXCAN_SetExtendedTimeSegments(base, bitrate);
	} else
#endif
	{
		/* Set time segments*/
		FLEXCAN_SetTimeSegments(base, bitrate);
	}

	FLEXCAN_ExitFreezeMode(base);
}

#if FEATURE_CAN_HAS_FD
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetBitrateCbt
 * Description   : Set FlexCAN bitrate.
 * This function will set up all the time segment values for the data phase of
 * FD frames. Those time segment values are passed in by the user and are based
 * on the required baudrate.
 *
 * Implements    : FLEXCAN_DRV_SetBitrateCbt_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetBitrateCbt(uint8_t instance,
		const flexcan_time_segment_t *bitrate) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(bitrate != NULL);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	/* Set time segments*/
	FLEXCAN_SetFDTimeSegments(base, bitrate);

	FLEXCAN_ExitFreezeMode(base);
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetBitrate
 * Description   : Get FlexCAN baudrate.
 * This function will be return the current bit rate settings for classical frames
 * or the arbitration phase of FD frames.
 *
 * Implements    : FLEXCAN_DRV_GetBitrate_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_GetBitrate(uint8_t instance, flexcan_time_segment_t *bitrate) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(bitrate != NULL);

	const CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FD
	if (true == FLEXCAN_IsFDEnabled(base)) {
		/* Get the Extended time segments*/
		FLEXCAN_GetExtendedTimeSegments(base, bitrate);
	} else
#endif
	{
		/* Get the time segments*/
		FLEXCAN_GetTimeSegments(base, bitrate);
	}
}

#if FEATURE_CAN_HAS_FD
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetBitrateFD
 * Description   : Get FlexCAN baudrate.
 * This function will be return the current bit rate settings for the data phase
 * of FD frames.
 *
 * Implements    : FLEXCAN_DRV_GetBitrateFD_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_GetBitrateFD(uint8_t instance, flexcan_time_segment_t *bitrate) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(bitrate != NULL);

	const CAN_Type * base = g_flexcanBase[instance];

	/* Get the time segments*/
	FLEXCAN_GetFDTimeSegments(base, bitrate);

}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetMasktype
 * Description   : Set RX masking type.
 * This function will set RX masking type as RX global mask or RX individual
 * mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxMaskType_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetRxMaskType(uint8_t instance, flexcan_rx_mask_type_t type) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	FLEXCAN_SetRxMaskType(base, type);

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetRxFifoGlobalMask
 * Description   : Set Rx FIFO global mask as the 11-bit standard mask or the
 * 29-bit extended mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxFifoGlobalMask_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetRxFifoGlobalMask(uint8_t instance,
		flexcan_msgbuff_id_type_t id_type, uint32_t mask) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	flexcan_rx_fifo_id_element_format_t formatType;
	CAN_Type * base = g_flexcanBase[instance];
	uint32_t calcMask = 0U;

	FLEXCAN_EnterFreezeMode(base);

	if (true == FLEXCAN_IsRxFifoEnabled(base)) {
		formatType = FLEXCAN_GetRxFifoIdFormat(base);
		calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType, mask);

		switch (formatType) {
		case FLEXCAN_RX_FIFO_ID_FORMAT_A:
			FLEXCAN_SetRxFifoGlobalMask(base, calcMask);
			break;
		case FLEXCAN_RX_FIFO_ID_FORMAT_B:
			FLEXCAN_SetRxFifoGlobalMask(base,
					(calcMask
							| (calcMask
									>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));
			break;
		case FLEXCAN_RX_FIFO_ID_FORMAT_C:
			FLEXCAN_SetRxFifoGlobalMask(base,
					(calcMask
							| (calcMask
									>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1)
							| (calcMask
									>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2)
							| (calcMask
									>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));
			break;
		default:
			/* Will Enable all filter fields mask */
			FLEXCAN_SetRxFifoGlobalMask(base, 0xFFFFFFFFU);
			break;
		}
	}
	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetRxMbGlobalMask
 * Description   : Set Rx Message Buffer global mask as the 11-bit standard mask
 * or the 29-bit extended mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxMbGlobalMask_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetRxMbGlobalMask(uint8_t instance,
		flexcan_msgbuff_id_type_t id_type, uint32_t mask) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	if (id_type == FLEXCAN_MSG_ID_STD) {
		/* Set standard global mask for RX MB*/
		FLEXCAN_SetRxMsgBuffGlobalStdMask(base, mask);
	} else if (id_type == FLEXCAN_MSG_ID_EXT) {
		/* Set extended global mask for RX MB*/
		FLEXCAN_SetRxMsgBuffGlobalExtMask(base, mask);
	} else {
		/* Should not get here */
	}

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetRxMb14Mask
 * Description   : Set Rx Message Buffer 14 mask as the 11-bit standard mask
 * or the 29-bit extended mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxMb14Mask_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetRxMb14Mask(uint8_t instance,
		flexcan_msgbuff_id_type_t id_type, uint32_t mask) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	if (id_type == FLEXCAN_MSG_ID_STD) {
		/* Set standard global mask for RX MB*/
		FLEXCAN_SetRxMsgBuff14StdMask(base, mask);
	} else if (id_type == FLEXCAN_MSG_ID_EXT) {
		/* Set extended global mask for RX MB*/
		FLEXCAN_SetRxMsgBuff14ExtMask(base, mask);
	} else {
		/* Should not get here */
	}

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetRxMb15Mask
 * Description   : Set Rx Message Buffer 15 mask as the 11-bit standard mask
 * or the 29-bit extended mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxMb15Mask_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetRxMb15Mask(uint8_t instance,
		flexcan_msgbuff_id_type_t id_type, uint32_t mask) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	if (id_type == FLEXCAN_MSG_ID_STD) {
		/* Set standard global mask for RX MB*/
		FLEXCAN_SetRxMsgBuff15StdMask(base, mask);
	} else if (id_type == FLEXCAN_MSG_ID_EXT) {
		/* Set extended global mask for RX MB*/
		FLEXCAN_SetRxMsgBuff15ExtMask(base, mask);
	} else {
		/* Should not get here */
	}

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetRxIndividualMask
 * Description   : Set Rx individual mask as the 11-bit standard mask or the
 * 29-bit extended mask.
 *
 * Implements    : FLEXCAN_DRV_SetRxIndividualMask_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_SetRxIndividualMask(uint8_t instance,
		flexcan_msgbuff_id_type_t id_type, uint8_t mb_idx, uint32_t mask) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	if ((mb_idx > FLEXCAN_GetMaxMsgBuffNum(base))
			|| (mb_idx >= CAN_RXIMR_COUNT)) {
		FLEXCAN_ExitFreezeMode(base);
		return STATUS_CAN_BUFF_OUT_OF_RANGE;
	}

	if (false == FLEXCAN_IsRxFifoEnabled(base)) {
		if (id_type == FLEXCAN_MSG_ID_STD) {
			/* Set standard individual mask*/
			FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);
		} else if (id_type == FLEXCAN_MSG_ID_EXT) {
			/* Set extended individual mask*/
			FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);
		} else {
			/* Should not get here */
		}
	} else {
		if (mb_idx <= FLEXCAN_GetNoOfIndividualMBsRxFIFO(base)) {
			/* In FIFO Mode get the Id Filter Format already configured by FLEXCAN_DRV_ConfigRxFifo */
			flexcan_rx_fifo_id_element_format_t formatType =
					FLEXCAN_GetRxFifoIdFormat(base);
			uint32_t calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType,
					mask);

			switch (formatType) {
			case FLEXCAN_RX_FIFO_ID_FORMAT_A:
				FLEXCAN_SetRxIndividualMask(base, mb_idx, calcMask);
				break;
			case FLEXCAN_RX_FIFO_ID_FORMAT_B:
				FLEXCAN_SetRxIndividualMask(base, mb_idx,
						(calcMask
								| (calcMask
										>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));
				break;
			case FLEXCAN_RX_FIFO_ID_FORMAT_C:
				FLEXCAN_SetRxIndividualMask(base, mb_idx,
						(calcMask
								| (calcMask
										>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1)
								| (calcMask
										>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2)
								| (calcMask
										>> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));
				break;
			default:
				/* Will Enable all filter fields mask */
				FLEXCAN_SetRxIndividualMask(base, mb_idx, 0xFFFFFFFFU);
				break;
			}
		} else {
			if (id_type == FLEXCAN_MSG_ID_STD) {
				/* Set standard individual mask*/
				FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);
			} else if (id_type == FLEXCAN_MSG_ID_EXT) {
				/* Set extended individual mask*/
				FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);
			} else {
				/* Should not get here */
			}
		}

	}

	FLEXCAN_ExitFreezeMode(base);

	return STATUS_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_EnableIRQs
 * Description   : This function enable FLEXCAN instance Interrupts
 *
 *END**************************************************************************/
static inline void FLEXCAN_EnableIRQs(uint8_t instance) {
	uint8_t i;
#if FEATURE_CAN_HAS_WAKE_UP_IRQ
	if (g_flexcanWakeUpIrqId[instance] != NotAvail_IRQn) {
		INT_SYS_EnableIRQ(g_flexcanWakeUpIrqId[instance]);
	}
#endif
	INT_SYS_EnableIRQ(g_flexcanErrorIrqId[instance]);
	INT_SYS_EnableIRQ(g_flexcanBusOffIrqId[instance]);
	for (i = 0; i < FEATURE_CAN_MB_IRQS_MAX_COUNT; i++) {
		if (g_flexcanOredMessageBufferIrqId[i][instance] != NotAvail_IRQn) {
			INT_SYS_EnableIRQ(g_flexcanOredMessageBufferIrqId[i][instance]);
		}
	}
}

#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_Errata10368
 * Description   : Implements errata 10368. This errata applies to mask 0N78S for MPC5748G CPU.
 *
 *END**************************************************************************/
static inline void FLEXCAN_Errata10368(uint8_t instance,
		const flexcan_user_config_t *data)
{
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_time_segment_t bitrate;

	if (data->fd_enable)
	{
		flexcan_msgbuff_code_status_t messageBuff= {
			.code = FLEXCAN_TX_REMOTE,
			.msgIdType = FLEXCAN_MSG_ID_STD,
			.dataLen = 1U,
			.fd_enable = false,
			.fd_padding = 0U,
			.enable_brs = false
		};
		uint8_t dummy_data[16];
		/* Enable Self Reception */
		FLEXCAN_SetSelfReception(base, true);

		/* Select Loopback mode */
		FLEXCAN_SetOperationMode(base, FLEXCAN_LOOPBACK_MODE);
		/* Dummy transmission on MB0 */
		(void)FLEXCAN_SetTxMsgBuff(base, 0U, &messageBuff, 0x1U, dummy_data);
		FLEXCAN_SetFDEnabled(base, true);
		bitrate = data->bitrate;
		FLEXCAN_SetExtendedTimeSegments(base, &bitrate);
		bitrate = data->bitrate_cbt;
		FLEXCAN_SetFDTimeSegments(base, &bitrate);
		FLEXCAN_ExitFreezeMode(base);
		/* Wait transmission of MB0 to complete */
		while((base->IFLAG1 & 0x1U) != 0x1U) {};
		/* Clear Transmission Complete */
		base->IFLAG1 = base->IFLAG1 | 0x1U;
		FLEXCAN_EnterFreezeMode(base);
	}
}
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_Init
 * Description   : Initialize FlexCAN driver.
 * This function will select a source clock, reset FlexCAN module, set maximum
 * number of message buffers, initialize all message buffers as inactive, enable
 * RX FIFO if needed, mask all mask bits, disable all MB interrupts, enable
 * FlexCAN normal mode, and enable all the error interrupts if needed.
 *
 * Implements    : FLEXCAN_DRV_Init_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_Init(uint8_t instance, flexcan_state_t *state,
		const flexcan_user_config_t *data) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(state != NULL);
	DEV_ASSERT(g_flexcanStatePtr[instance] == NULL);
#ifdef ERRATA_E10595
	if (instance != 0U)
	{
		DEV_ASSERT((MC_ME->GS & MC_ME_GS_S_FXOSC_MASK) != 0U);
	}
#endif

	status_t result;
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_time_segment_t bitrate;
	status_t osifStat;
	uint32_t i, j;

	if (FLEXCAN_IsEnabled(base)) {
		/* To enter Disable Mode requires FreezMode first */
		FLEXCAN_EnterFreezeMode(base);
		FLEXCAN_Disable(base);
	}

#if FEATURE_CAN_HAS_PE_CLKSRC_SELECT
	/* Select a source clock for the FlexCAN engine */
	FLEXCAN_SelectClock(base, data->pe_clock);
#endif

	/* Enable the CAN clock */
	FLEXCAN_Enable(base);

	FLEXCAN_EnterFreezeMode(base);

	/* Initialize FLEXCAN device */
	FLEXCAN_Init(base);

#ifdef ERRATA_E10368
#if FEATURE_CAN_HAS_FD
	FLEXCAN_Errata10368(instance, data);
#endif /* FEATURE_CAN_HAS_FD */
#endif /* ERRATA_E10368 */

#if FEATURE_CAN_HAS_FD
	/* Enable/Disable FD and check FD was set as expected. Setting FD as enabled
	 * might fail if the current CAN instance does not support FD. */
	FLEXCAN_SetFDEnabled(base, data->fd_enable);
	if (FLEXCAN_IsFDEnabled(base) != data->fd_enable) {
		return STATUS_ERROR;
	}

	/* If the FD feature is enabled, enable the Stuff Bit Count, in order to be
	 * ISO-compliant. */
	FLEXCAN_SetStuffBitCount(base, data->fd_enable);
#endif

	/* Disable the self reception feature if FlexCAN is not in loopback mode. */
	if (data->flexcanMode != FLEXCAN_LOOPBACK_MODE) {
		FLEXCAN_SetSelfReception(base, false);
	}

	/* Enable RxFIFO feature, if requested. This might fail if the FD mode is
	 * enabled. */
	if (data->is_rx_fifo_needed) {
		result = FLEXCAN_EnableRxFifo(base, (uint32_t) data->num_id_filters);
		if (result != STATUS_SUCCESS) {
			return result;
		}
	}

#if FEATURE_CAN_HAS_DMA_ENABLE
	/* Enable DMA support for RxFIFO transfer, if requested. */
	if (data->transfer_type == FLEXCAN_RXFIFO_USING_DMA) {
		if (FLEXCAN_IsRxFifoEnabled(base)) {
			FLEXCAN_SetRxFifoDMA(base, true);
		} else {
			return STATUS_ERROR;
		}
	}
	if (data->transfer_type == FLEXCAN_RXFIFO_USING_INTERRUPTS) {
		FLEXCAN_SetRxFifoDMA(base, false);
	}
#endif

#if FEATURE_CAN_HAS_FD
	/* Set payload size. */
	FLEXCAN_SetPayloadSize(base, data->payload);
#endif

	result = FLEXCAN_SetMaxMsgBuffNum(base, data->max_num_mb);
	if (result != STATUS_SUCCESS) {
		return result;
	}

#if FEATURE_CAN_HAS_FD
	/* Set bit rate. */
	if (FLEXCAN_IsFDEnabled(base)) {
		bitrate = data->bitrate;
		FLEXCAN_SetExtendedTimeSegments(base, &bitrate);
		bitrate = data->bitrate_cbt;
		FLEXCAN_SetFDTimeSegments(base, &bitrate);
	} else
#endif
	{
		bitrate = data->bitrate;
		FLEXCAN_SetTimeSegments(base, &bitrate);
	}

	/* Select mode */
	FLEXCAN_SetOperationMode(base, data->flexcanMode);

	if (data->flexcanMode != FLEXCAN_FREEZE_MODE) {
		FLEXCAN_ExitFreezeMode(base);
	}

	/* Enable FlexCAN interrupts.*/
	FLEXCAN_EnableIRQs(instance);

	for (i = 0; i < FEATURE_CAN_MAX_MB_NUM; i++) {
		osifStat = OSIF_SemaCreate(&state->mbs[i].mbSema, 0U);
		if (osifStat != STATUS_SUCCESS) {
			for (j = 0; j < i; j++) {
				(void) OSIF_SemaDestroy(&state->mbs[j].mbSema);
			}
			return STATUS_ERROR;
		}
		state->mbs[i].isBlocking = false;
		state->mbs[i].mb_message = NULL;
		state->mbs[i].state = FLEXCAN_MB_IDLE;
	}
#if FEATURE_CAN_HAS_MEM_ERR_DET
	FLEXCAN_DisableMemErrorDetection(base);
#endif

	/* Store transfer type and DMA channel number used in transfer */
	state->transferType = data->transfer_type;
#if FEATURE_CAN_HAS_DMA_ENABLE
	state->rxFifoDMAChannel = data->rxFifoDMAChannel;
#endif

	/* Clear Callbacks in case of autovariables garbage */
	state->callback = NULL;
	state->callbackParam = NULL;
	state->error_callback = NULL;
	state->errorCallbackParam = NULL;

	/* Save runtime structure pointers so irq handler can point to the correct state structure */
	g_flexcanStatePtr[instance] = state;

	return (STATUS_SUCCESS);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigTxMb
 * Description   : Configure a Tx message buffer.
 * This function will first check if RX FIFO is enabled. If RX FIFO is enabled,
 * the function will make sure if the MB requested is not occupied by RX FIFO
 * and ID filter table. Then this function will set up the message buffer fields,
 * configure the message buffer code for Tx buffer as INACTIVE, and enable the
 * Message Buffer interrupt.
 *
 * Implements    : FLEXCAN_DRV_ConfigTxMb_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_ConfigTxMb(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(tx_info != NULL);

	flexcan_msgbuff_code_status_t cs;
	CAN_Type * base = g_flexcanBase[instance];

	/* Initialize transmit mb*/
	cs.dataLen = tx_info->data_length;
	cs.msgIdType = tx_info->msg_id_type;
#if FEATURE_CAN_HAS_FD
	cs.enable_brs = tx_info->enable_brs;
	cs.fd_enable = tx_info->fd_enable;
	cs.fd_padding = tx_info->fd_padding;
#endif

	cs.code = (uint32_t) FLEXCAN_TX_INACTIVE;

	return FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, NULL);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigRemoteResponseMb
 * Description   : Configures a transmit message buffer for remote frame
 * response. This function will first check if RX FIFO is enabled. If RX FIFO is
 * enabled, the function will make sure if the MB requested is not occupied by
 * the RX FIFO and ID filter table. Then this function will set up the message
 * buffer fields, configure the message buffer code for Tx buffer as RX_RANSWER,
 * and enable the Message Buffer interrupt.
 *
 * Implements    : FLEXCAN_DRV_ConfigRemoteResponseMb_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_ConfigRemoteResponseMb(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id,
		const uint8_t *mb_data) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(tx_info != NULL);

	flexcan_msgbuff_code_status_t cs;
	CAN_Type * base = g_flexcanBase[instance];

	/* Initialize transmit mb*/
	cs.dataLen = tx_info->data_length;
	cs.msgIdType = tx_info->msg_id_type;
	cs.code = (uint32_t) FLEXCAN_RX_RANSWER;

	FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

	return FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, mb_data);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SendBlocking
 * Description   : This function sends a CAN frame using a configured message
 * buffer. The function blocks until either the frame was sent, or the specified
 * timeout expired.
 *
 * Implements    : FLEXCAN_DRV_SendBlocking_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_SendBlocking(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id,
		const uint8_t *mb_data, uint32_t timeout_ms) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(tx_info != NULL);

	status_t result;
	flexcan_state_t * state = g_flexcanStatePtr[instance];
	CAN_Type * base = g_flexcanBase[instance];

	result = FLEXCAN_StartSendData(instance, mb_idx, tx_info, msg_id, mb_data,
			true);

	if (result == STATUS_SUCCESS) {
		status_t status;

		/* Enable message buffer interrupt*/
		(void) FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);

		status = OSIF_SemaWait(&state->mbs[mb_idx].mbSema, timeout_ms);

		if (status == STATUS_TIMEOUT) {
			if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE) {
				/* Disable message buffer interrupt */
				(void) FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);
				/* Clear message buffer flag */
				FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
				FLEXCAN_AbortTxMsgBuff(base, mb_idx);
				uint32_t flexcan_mb_config;

#ifndef ERRATA_E9527
				/* Wait to finish abort operation */
				while (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U) {
					/* Do Nothing wait for the flag */
				}
#endif
				volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(
						base, mb_idx);
				flexcan_mb_config = *flexcan_mb;
				/* Check if the MBs have been safely Inactivated */
				if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT)
						== (uint32_t) FLEXCAN_TX_INACTIVE) {
#ifndef ERRATA_E9527
					/* Transmission have occurred */
					result = STATUS_SUCCESS;
#else
					/* Transmission have not occurred because it uses the inactivation operation */
					if (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
					{
						result = STATUS_TIMEOUT;
					}
					else
					{
						result = STATUS_SUCCESS;
					}
#endif
				}
				if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT)
						== (uint32_t) FLEXCAN_TX_ABORT) {
					/* Transmission have occurred */
					result = STATUS_TIMEOUT;
				}
				/* Clear message buffer flag */
				FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
				state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
			}
		}
	}
	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_Send
 * Description   : This function sends a CAN frame using a configured message
 * buffer. The function returns immediately. If a callback is installed, it will
 * be invoked after the frame was sent.
 *
 * Implements    : FLEXCAN_DRV_Send_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_Send(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id,
		const uint8_t *mb_data) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(tx_info != NULL);

	status_t result;
	CAN_Type * base = g_flexcanBase[instance];

	result = FLEXCAN_StartSendData(instance, mb_idx, tx_info, msg_id, mb_data,
			false);
	if (result == STATUS_SUCCESS) {
		/* Enable message buffer interrupt*/
		result = FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);
	}

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigMb
 * Description   : Configure a Rx message buffer.
 * This function will first check if RX FIFO is enabled. If RX FIFO is enabled,
 * the function will make sure if the MB requested is not occupied by RX FIFO
 * and ID filter table. Then this function will set up the message buffer fields,
 * configure the message buffer code for Rx message buffer as NOT_USED, enable
 * the Message Buffer interrupt, configure the message buffer code for Rx
 * message buffer as INACTIVE, copy user's buffer into the message buffer data
 * area, and configure the message buffer code for Rx message buffer as EMPTY.
 *
 * Implements    : FLEXCAN_DRV_ConfigRxMb_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_ConfigRxMb(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *rx_info, uint32_t msg_id) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(rx_info != NULL);

	status_t result;
	flexcan_msgbuff_code_status_t cs;
	CAN_Type * base = g_flexcanBase[instance];

	cs.dataLen = rx_info->data_length;
	cs.msgIdType = rx_info->msg_id_type;
#if FEATURE_CAN_HAS_FD
	cs.fd_enable = rx_info->fd_enable;
#endif
	/* Initialize rx mb*/
	cs.code = (uint32_t) FLEXCAN_RX_NOT_USED;
	result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);

	if (result == STATUS_SUCCESS) {
		/* Initialize receive MB*/
		cs.code = (uint32_t) FLEXCAN_RX_INACTIVE;
		result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);
	}

	if (result == STATUS_SUCCESS) {
		/* Set up FlexCAN message buffer fields for receiving data*/
		cs.code = (uint32_t) FLEXCAN_RX_EMPTY;
		result = FLEXCAN_SetRxMsgBuff(base, mb_idx, &cs, msg_id);
	}
	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigRxFifo
 * Description   : Confgure RX FIFO ID filter table elements.
 * This function will confgure RX FIFO ID filter table elements, and enable RX
 * FIFO interrupts.
 *
 * Implements    : FLEXCAN_DRV_ConfigRxFifo_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_ConfigRxFifo(uint8_t instance,
		flexcan_rx_fifo_id_element_format_t id_format,
		const flexcan_id_table_t *id_filter_table) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	/* Initialize rx fifo*/
	FLEXCAN_SetRxFifoFilter(base, id_format, id_filter_table);

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ReceiveBlocking
 * Description   : This function receives a CAN frame into a configured message
 * buffer. The function blocks until either a frame was received, or the
 * specified timeout expired.
 *
 * Implements    : FLEXCAN_DRV_ReceiveBlocking_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_ReceiveBlocking(uint8_t instance, uint8_t mb_idx,
		flexcan_msgbuff_t *data, uint32_t timeout_ms) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	status_t result;
	flexcan_state_t * state = g_flexcanStatePtr[instance];
	CAN_Type * base = g_flexcanBase[instance];

	result = FLEXCAN_StartRxMessageBufferData(instance, mb_idx, data, true);

	if (result == STATUS_SUCCESS) {
		status_t status;

		status = OSIF_SemaWait(&state->mbs[mb_idx].mbSema, timeout_ms);

		if (status == STATUS_TIMEOUT) {
			/* If the flag is set Successful reception else report TimeOut */
			if (FLEXCAN_GetMsgBuffIntStatusFlag(base, mb_idx) == (uint8_t) 0U) {
				result = STATUS_TIMEOUT;
			}
			/* Disable message buffer interrupt */
			(void) FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);
		}
		/* Consider the MB state has been changed by interrupt as frame received */
		if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE) {
			return STATUS_SUCCESS;
		}

		state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
	}

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_Receive
 * Description   : This function receives a CAN frame into a configured message
 * buffer. The function returns immediately. If a callback is installed, it will
 * be invoked after the frame was received and read into the specified buffer.
 *
 * Implements    : FLEXCAN_DRV_Receive_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_Receive(uint8_t instance, uint8_t mb_idx,
		flexcan_msgbuff_t *data) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	status_t result;

	result = FLEXCAN_StartRxMessageBufferData(instance, mb_idx, data, false);

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_RxFifoBlocking
 * Description   : This function receives a CAN frame using the Rx FIFO. The
 * function blocks until either a frame was received, or the specified timeout
 * expired.
 *
 * Implements    : FLEXCAN_DRV_RxFifoBlocking_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_RxFifoBlocking(uint8_t instance, flexcan_msgbuff_t *data,
		uint32_t timeout_ms) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	status_t result;
	flexcan_state_t * state = g_flexcanStatePtr[instance];
	CAN_Type * base = g_flexcanBase[instance];

	result = FLEXCAN_StartRxMessageFifoData(instance, data, true);

	if (result == STATUS_SUCCESS) {
		result = OSIF_SemaWait(&state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema,
				timeout_ms);

		if (result == STATUS_TIMEOUT) {
			/* If the status is updated reception successful else report TimeOut */
			if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE) {
				result = STATUS_SUCCESS;
			}
			/* Disable RX FIFO interrupts*/
			(void) FLEXCAN_SetMsgBuffIntCmd(base,
					FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
			(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING,
					false);
			(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW,
					false);

#if FEATURE_CAN_HAS_DMA_ENABLE
			/* Check if transfer is done over DMA and stop transfer */
			if ((state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state
					== FLEXCAN_MB_RX_BUSY)
					&& (state->transferType == FLEXCAN_RXFIFO_USING_DMA)) {
				/* This function always return status success */
				(void) EDMA_DRV_StopChannel(state->rxFifoDMAChannel);
			}
#endif
		}
		state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
	}

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_RxFifo
 * Description   : This function receives a CAN frame using the Rx FIFO. The
 * function returns immediately. If a callback is installed, it will be invoked
 * after the frame was received and read into the specified buffer.
 *
 * Implements    : FLEXCAN_DRV_RxFifo_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_RxFifo(uint8_t instance, flexcan_msgbuff_t *data) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	status_t result;

	result = FLEXCAN_StartRxMessageFifoData(instance, data, false);

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_Deinit
 * Description   : Shutdown a FlexCAN module.
 * This function will disable all FlexCAN interrupts, and disable the FlexCAN.
 *
 * Implements    : FLEXCAN_DRV_Deinit_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_Deinit(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	const flexcan_state_t * state = g_flexcanStatePtr[instance];
	status_t result = STATUS_SUCCESS;
	status_t osifStat;
	uint32_t i;

	/* Disable FlexCAN interrupts.*/
	if (state != NULL) {
		if (state->error_callback != NULL) {
			FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, false);
			FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, false);
			FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, false);
			FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, false);
		}
	}

#if FEATURE_CAN_HAS_WAKE_UP_IRQ
	if (g_flexcanWakeUpIrqId[instance] != NotAvail_IRQn) {
		INT_SYS_DisableIRQ(g_flexcanWakeUpIrqId[instance]);
	}
#endif
	INT_SYS_DisableIRQ(g_flexcanErrorIrqId[instance]);
	INT_SYS_DisableIRQ(g_flexcanBusOffIrqId[instance]);
	for (i = 0; i < FEATURE_CAN_MB_IRQS_MAX_COUNT; i++) {
		if (g_flexcanOredMessageBufferIrqId[i][instance] != NotAvail_IRQn) {
			INT_SYS_DisableIRQ(g_flexcanOredMessageBufferIrqId[i][instance]);
		}
	}

	if (FLEXCAN_IsEnabled(g_flexcanBase[instance])) {
		/* Enter Freeze Mode Required before to enter Disabled Mode */
		FLEXCAN_EnterFreezeMode(g_flexcanBase[instance]);
		/* Disable FlexCAN.*/
		FLEXCAN_Disable(g_flexcanBase[instance]);
		/* Check if the state have been initialized */
	}

	if (state != NULL) {
		for (i = 0; i < FEATURE_CAN_MAX_MB_NUM; i++) {
			osifStat = OSIF_SemaDestroy(&state->mbs[i].mbSema);
			if (osifStat != STATUS_SUCCESS) {
				result = STATUS_ERROR;
			}
		}
	}

	if (result == STATUS_SUCCESS) {
		/* Clear state pointer that is checked by FLEXCAN_DRV_Init */
		g_flexcanStatePtr[instance] = NULL;
	}

	return result;
}

#if FEATURE_CAN_HAS_FD
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_SetTDCOffset
 * Description   : Enables/Disables the Transceiver Delay Compensation feature and sets
 * the Transceiver Delay Compensation Offset.
 *
 * Implements    : FLEXCAN_DRV_SetTDCOffset_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_SetTDCOffset(uint8_t instance, bool enable, uint8_t offset) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	/* Enable/Disable TDC and set the TDC Offset */
	FLEXCAN_SetTDCOffset(base, enable, offset);

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetTDCValue
 * Description   : Gets the value of the Transceiver Delay Compensation.
 *
 * Implements    : FLEXCAN_DRV_GetTDCValue_Activity
 *END**************************************************************************/
uint8_t FLEXCAN_DRV_GetTDCValue(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	const CAN_Type * base = g_flexcanBase[instance];

	return (uint8_t) ((base->FDCTRL & CAN_FDCTRL_TDCVAL_MASK)
			>> CAN_FDCTRL_TDCVAL_SHIFT);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetTDCFail
 * Description   : Gets the value of the TDC Fail flag.
 *
 * Implements    : FLEXCAN_DRV_GetTDCFail_Activity
 *END**************************************************************************/
bool FLEXCAN_DRV_GetTDCFail(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	const CAN_Type * base = g_flexcanBase[instance];

	return (((base->FDCTRL & CAN_FDCTRL_TDCFAIL_MASK)
			>> CAN_FDCTRL_TDCFAIL_SHIFT) != 0U);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ClearTDCFail
 * Description   : Clears the TDC Fail flag.
 *
 * Implements    : FLEXCAN_DRV_ClearTDCFail_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_ClearTDCFail(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	base->FDCTRL = base->FDCTRL | CAN_FDCTRL_TDCFAIL_MASK;
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_IRQHandlerRxFIFO
 * Description   : Process IRQHandler in case of RxFIFO mode selection for CAN interface.
 *
 * Implements    : FLEXCAN_IRQHandlerRxFIFO_Activity
 *END**************************************************************************/
static inline void FLEXCAN_IRQHandlerRxFIFO(uint8_t instance, uint32_t mb_idx) {
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	if (mb_idx == FEATURE_CAN_RXFIFO_FRAME_AVAILABLE) {
		if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_RX_BUSY) {
			/* Get RX FIFO field values */
			FLEXCAN_ReadRxFifo(base,
					state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message);

			/* Complete receive data */
			FLEXCAN_CompleteRxMessageFifoData(instance);
			FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

			/* Invoke callback */
			if (state->callback != NULL) {
				state->callback(instance, FLEXCAN_EVENT_RXFIFO_COMPLETE,
				FLEXCAN_MB_HANDLE_RXFIFO, state);
			}
		}
	} else if (mb_idx == FEATURE_CAN_RXFIFO_WARNING) {
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

		/* Invoke callback */
		if (state->callback != NULL) {
			state->callback(instance, FLEXCAN_EVENT_RXFIFO_WARNING,
			FLEXCAN_MB_HANDLE_RXFIFO, state);
		}
	} else if (mb_idx == FEATURE_CAN_RXFIFO_OVERFLOW) {
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

		/* Invoke callback */
		if (state->callback != NULL) {
			state->callback(instance, FLEXCAN_EVENT_RXFIFO_OVERFLOW,
			FLEXCAN_MB_HANDLE_RXFIFO, state);
		}
	} else {
		/* Do Nothing */
	}

}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_IRQHandlerRxMB
 * Description   : Process IRQHandler in case of Rx MessageBuffer selection
 * for CAN interface.
 *
 * This is not a public API as it is called whenever an interrupt and receive
 * individual MB occurs
 *END**************************************************************************/
static inline void FLEXCAN_IRQHandlerRxMB(uint8_t instance, uint32_t mb_idx) {
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];
	status_t result = STATUS_SUCCESS;

	/* Lock RX message buffer and RX FIFO*/
	FLEXCAN_LockRxMsgBuff(base, mb_idx);

	/* Get RX MB field values*/
	result = FLEXCAN_GetMsgBuff(base, mb_idx, state->mbs[mb_idx].mb_message);

	if (result == STATUS_SUCCESS) {
		/* Unlock RX message buffer and RX FIFO*/
		FLEXCAN_UnlockRxMsgBuff(base);

		/* Complete receive data */
		FLEXCAN_CompleteTransfer(instance, mb_idx);
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

		/* Invoke callback */
		if (state->callback != NULL) {
			state->callback(instance, FLEXCAN_EVENT_RX_COMPLETE, mb_idx, state);
		}
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_IRQHandler
 * Description   : Interrupt handler for FLEXCAN.
 * This handler read data from MB or FIFO, and then clear the interrupt flags.
 * This is not a public API as it is called whenever an interrupt occurs.
 *
 *END**************************************************************************/
void FLEXCAN_IRQHandler(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	uint32_t flag_reg = 0;
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	/* Get the interrupts that are enabled and ready */
	uint32_t mb_idx = 0;
	flag_reg = FLEXCAN_GetMsgBuffIntStatusFlag(base, mb_idx);

	while ((flag_reg & 1U) == 0U) {
		mb_idx++;
		flag_reg = FLEXCAN_GetMsgBuffIntStatusFlag(base, mb_idx);

		if (mb_idx >= FEATURE_CAN_MAX_MB_NUM) {
			break;
		}
	}

	/* Check Tx/Rx interrupt flag and clear the interrupt */
	if (flag_reg != 0U) {

		if (FLEXCAN_IsRxFifoEnabled(base)
				&& (mb_idx <= FEATURE_CAN_RXFIFO_OVERFLOW)) {
			FLEXCAN_IRQHandlerRxFIFO(instance, mb_idx);
		} else {
			/* Check mailbox completed reception */
			if (state->mbs[mb_idx].state == FLEXCAN_MB_RX_BUSY) {
				FLEXCAN_IRQHandlerRxMB(instance, mb_idx);
			}
		}

		/* Check mailbox completed transmission */
		if (state->mbs[mb_idx].state == FLEXCAN_MB_TX_BUSY) {
			/* Complete transmit data */
			FLEXCAN_CompleteTransfer(instance, mb_idx);

			if (state->mbs[mb_idx].isRemote) {
				/* If the frame was a remote frame, clear the flag only if the response was
				 * not received yet. If the response was received, leave the flag set in order
				 * to be handled when the user calls FLEXCAN_DRV_RxMessageBuffer. */
				flexcan_msgbuff_t mb;
				FLEXCAN_LockRxMsgBuff(base, mb_idx);
				(void) FLEXCAN_GetMsgBuff(base, mb_idx, &mb);
				FLEXCAN_UnlockRxMsgBuff(base);

				if (((mb.cs & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT)
						== (uint32_t) FLEXCAN_RX_EMPTY) {
					FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
				}
			} else {
				FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
			}

			/* Invoke callback */
			if (state->callback != NULL) {
				state->callback(instance, FLEXCAN_EVENT_TX_COMPLETE, mb_idx,
						state);
			}
		}
	} else {
#if FEATURE_CAN_HAS_PRETENDED_NETWORKING
		/* The pretending Network Feature is present on all CPUs
		 * only on FLEXCAN Instance 0   */
		if (instance == 0U) {
			uint8_t wtof = FLEXCAN_GetWTOF(base);
			uint8_t wumf = FLEXCAN_GetWUMF(base);

			/* Check if wake-up event occurred */
			if ((wtof != 0U) || (wumf != 0U)) {
				FLEXCAN_WakeUpHandler(instance);
			}
		}
#endif
		uint32_t ecr = FLEXCAN_GetErrorCounters(base);

		/* Check if any error occurred */
		if (ecr != 0U) {
			FLEXCAN_Error_IRQHandler(instance);
		}
	}

	return;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_Error_IRQHandler
 * Description   : Error interrupt handler for FLEXCAN.
 * This handler read data from MB or FIFO, and then clear the interrupt flags.
 * This is not a public API as it is called whenever an interrupt occurs.
 *
 *END**************************************************************************/
void FLEXCAN_Error_IRQHandler(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	/* Invoke callback */
	if (state->error_callback != NULL) {
		state->error_callback(instance, FLEXCAN_EVENT_ERROR, state);
	}

	/* Clear all other interrupts in ESR1 register (Error, Busoff, Wakeup) */
	FLEXCAN_ClearErrIntStatusFlag(base);

	return;
}

#if FEATURE_CAN_HAS_WAKE_UP_IRQ

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_WakeUpHandler
 * Description   : Wake up handler for FLEXCAN.
 * This handler verifies the event which caused the wake up and invokes the
 * user callback, if configured.
 * This is not a public API as it is called whenever an wake up event occurs.
 *
 *END**************************************************************************/
void FLEXCAN_WakeUpHandler(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING
	if (FLEXCAN_IsPNEnabled(base)) {
		if (FLEXCAN_GetWTOF(base) != 0U) {
			FLEXCAN_ClearWTOF(base);
			/* Invoke callback */
			if (state->callback != NULL) {
				state->callback(instance, FLEXCAN_EVENT_WAKEUP_TIMEOUT, 0U,
						state);
			}
		}
		if (FLEXCAN_GetWUMF(base) != 0U) {
			FLEXCAN_ClearWUMF(base);
			/* Invoke callback */
			if (state->callback != NULL) {
				state->callback(instance, FLEXCAN_EVENT_WAKEUP_MATCH, 0U,
						state);
			}
		}
	}
#endif

#if FEATURE_CAN_HAS_SELF_WAKE_UP
	if (FLEXCAN_IsSelfWakeUpEnabled(base))
	{
		if (FLEXCAN_GetWAKINT(base) != 0U)
		{
			FLEXCAN_ClearWAKINT(base);
			/* Invoke callback */
			if (state->callback != NULL)
			{
				state->callback(instance, FLEXCAN_EVENT_SELF_WAKEUP, 0U, state);
			}
		}
	}
#endif
}
#endif /* FEATURE_CAN_HAS_WAKE_UP_IRQ */

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetTransferStatus
 * Description   : This function returns whether the previous FLEXCAN receive is
 *                 completed.
 * When performing a non-blocking receive, the user can call this function to
 * ascertain the state of the current receive progress: in progress (or busy)
 * or complete (success).
 *
 * Implements    : FLEXCAN_DRV_GetTransferStatus_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_GetTransferStatus(uint8_t instance, uint8_t mb_idx) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	const flexcan_state_t * state = g_flexcanStatePtr[instance];
	status_t status;

	if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE) {
		status = STATUS_SUCCESS;
	}
#if FEATURE_CAN_HAS_DMA_ENABLE
	else if (state->mbs[mb_idx].state == FLEXCAN_MB_DMA_ERROR) {
		status = STATUS_ERROR;
	}
#endif
	else {
		status = STATUS_BUSY;
	}

	return status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetErrorStatus
 * Description   : Reports various error conditions detected in the reception and
 *                 transmission of a CAN frame and some general status of the device.
 *
 * Implements    : FLEXCAN_DRV_GetErrorStatus_Activity
 *END**************************************************************************/
uint32_t FLEXCAN_DRV_GetErrorStatus(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	const CAN_Type * base = g_flexcanBase[instance];

	return ((uint32_t) (base->ESR1));
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_AbortTransfer
 * Description   : This function shuts down the FLEXCAN by disabling interrupts and
 *                 the transmitter/receiver.
 * This function disables the FLEXCAN interrupts, disables the transmitter and
 * receiver.
 *
 * Implements    : FLEXCAN_DRV_AbortTransfer_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_AbortTransfer(uint8_t instance, uint8_t mb_idx) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	flexcan_state_t * state = g_flexcanStatePtr[instance];
	CAN_Type * base = g_flexcanBase[instance];

	/* Check if a transfer is running. */
	if (state->mbs[mb_idx].state == FLEXCAN_MB_IDLE) {
		return STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
	}

	if (state->mbs[mb_idx].state == FLEXCAN_MB_TX_BUSY) {
		status_t result = STATUS_SUCCESS;
		/* Stop the running transfer. */
		FLEXCAN_CompleteTransfer(instance, mb_idx);
		/* Clear message buffer flag */
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
		FLEXCAN_AbortTxMsgBuff(base, mb_idx);
		uint32_t flexcan_mb_config;

#ifndef ERRATA_E9527
		/* Wait to finish abort operation */
		while (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U) {
			/* Do Nothing wait for the flag */
		}
#endif
		volatile const uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base,
				mb_idx);
		flexcan_mb_config = *flexcan_mb;
		/* Check if the MBs have been safely Inactivated */
		if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT)
				== (uint32_t) FLEXCAN_TX_INACTIVE) {
#ifndef ERRATA_E9527
			/* Transmission have occurred */
			result = STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
#else
			/* Transmission have not occurred because it uses the inactivation operation */
			if (FLEXCAN_GetBuffStatusFlag(base, mb_idx) == 0U)
			{
				result = STATUS_SUCCESS;
			}
			else
			{
				result = STATUS_CAN_NO_TRANSFER_IN_PROGRESS;
			}
#endif
		}
		if (((flexcan_mb_config & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT)
				== (uint32_t) FLEXCAN_TX_ABORT) {
			/* Transmission have been aborted */
			result = STATUS_SUCCESS;
		}
		/* Clear message buffer flag */
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
		state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
		return result;
	}

	if (state->mbs[mb_idx].state == FLEXCAN_MB_RX_BUSY) {
		/* Stop the running transfer. */
		FLEXCAN_CompleteTransfer(instance, mb_idx);

		if (FLEXCAN_IsRxFifoEnabled(base) == true) {

			/* Get the number of RX FIFO Filters*/
			uint32_t val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK)
					>> CAN_CTRL2_RFFN_SHIFT);
			/* Get the number if MBs occupied by RX FIFO and ID filter table*/
			/* the Rx FIFO occupies the memory space originally reserved for MB0-5*/
			/* Every number of RFFN means 8 number of RX FIFO filters*/
			/* and every 4 number of RX FIFO filters occupied one MB*/
			uint32_t val2 = RxFifoOcuppiedLastMsgBuff(val1);
			if (mb_idx > val2) {
				/* This operation is not allowed for MB that are part of RxFIFO */
				FLEXCAN_ResetRxMsgBuff(base, mb_idx);
			}
			if (mb_idx == FLEXCAN_MB_HANDLE_RXFIFO) {
				/* Disable RX FIFO interrupts*/
				(void) FLEXCAN_SetMsgBuffIntCmd(base,
						FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
#if FEATURE_CAN_HAS_DMA_ENABLE
				if (state->transferType == FLEXCAN_RXFIFO_USING_DMA) {
					(void) EDMA_DRV_StopChannel(state->rxFifoDMAChannel);
				}
#endif
			}
		} else {
			/* This operation is not allowed for MB that are part of RxFIFO */
			FLEXCAN_ResetRxMsgBuff(base, mb_idx);
		}
	}

	if (FLEXCAN_GetMsgBuffIntStatus(base, mb_idx) == 1U) {
		/* Stop the running transfer. */
		FLEXCAN_CompleteTransfer(instance, mb_idx);
		/* Clear message buffer flag */
		FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);
	}

	return STATUS_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_StartSendData
 * Description   : Initiate (start) a transmit by beginning the process of
 * sending data.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static status_t FLEXCAN_StartSendData(uint8_t instance, uint8_t mb_idx,
		const flexcan_data_info_t *tx_info, uint32_t msg_id,
		const uint8_t *mb_data,
		bool isBlocking) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(tx_info != NULL);

	status_t result;
	flexcan_msgbuff_code_status_t cs;
	flexcan_state_t * state = g_flexcanStatePtr[instance];
	CAN_Type * base = g_flexcanBase[instance];

	if (mb_idx >= FLEXCAN_GetMaxMbNum(base)) {
		return STATUS_CAN_BUFF_OUT_OF_RANGE;
	}

	if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE) {
		return STATUS_BUSY;
	}

	/* Clear message buffer flag */
	FLEXCAN_ClearMsgBuffIntStatusFlag(base, mb_idx);

	state->mbs[mb_idx].state = FLEXCAN_MB_TX_BUSY;
	state->mbs[mb_idx].isBlocking = isBlocking;
	state->mbs[mb_idx].isRemote = tx_info->is_remote;

	cs.dataLen = tx_info->data_length;
	cs.msgIdType = tx_info->msg_id_type;

#if FEATURE_CAN_HAS_FD
	cs.fd_enable = tx_info->fd_enable;
	cs.fd_padding = tx_info->fd_padding;
	cs.enable_brs = tx_info->enable_brs;
#endif

	if (tx_info->is_remote) {
		cs.code = (uint32_t) FLEXCAN_TX_REMOTE;
	} else {
		cs.code = (uint32_t) FLEXCAN_TX_DATA;
	}
	result = FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, mb_data);

	if (result != STATUS_SUCCESS) {
		state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
	}

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_StartRxMessageBufferData
 * Description   : Initiate (start) a receive by beginning the process of
 * receiving data and enabling the interrupt.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static status_t FLEXCAN_StartRxMessageBufferData(uint8_t instance,
		uint8_t mb_idx, flexcan_msgbuff_t *data,
		bool isBlocking) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	status_t result = STATUS_SUCCESS;
	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	/* Check if the MB index is in range */
	if (mb_idx >= FLEXCAN_GetMaxMbNum(base)) {
		return STATUS_CAN_BUFF_OUT_OF_RANGE;
	}

	/* Check if RX FIFO is enabled*/
	if (FLEXCAN_IsRxFifoEnabled(base) == true) {
		uint32_t val1, val2;
		/* Get the number of RX FIFO Filters*/
		val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
		/* Get the number if MBs occupied by RX FIFO and ID filter table*/
		/* the Rx FIFO occupies the memory space originally reserved for MB0-5*/
		/* Every number of RFFN means 8 number of RX FIFO filters*/
		/* and every 4 number of RX FIFO filters occupied one MB*/
		val2 = RxFifoOcuppiedLastMsgBuff(val1);

		if (mb_idx <= val2) {
			return STATUS_CAN_BUFF_OUT_OF_RANGE;
		}
	}

	/* Start receiving mailbox */
	if (state->mbs[mb_idx].state != FLEXCAN_MB_IDLE) {
		return STATUS_BUSY;
	}
	state->mbs[mb_idx].state = FLEXCAN_MB_RX_BUSY;
	state->mbs[mb_idx].mb_message = data;
	state->mbs[mb_idx].isBlocking = isBlocking;

	/* Enable MB interrupt*/
	result = FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, true);

	if (result != STATUS_SUCCESS) {
		state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
	}

	return result;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_StartRxMessageFifoData
 * Description   : Initiate (start) a receive by beginning the process of
 * receiving data and enabling the interrupt.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static status_t FLEXCAN_StartRxMessageFifoData(uint8_t instance,
		flexcan_msgbuff_t *data,
		bool isBlocking) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];
#if FEATURE_CAN_HAS_DMA_ENABLE
	status_t edmaStat;

	if (state->transferType == FLEXCAN_RXFIFO_USING_DMA) {
		if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state
				== FLEXCAN_MB_DMA_ERROR) {
			/* Check if FIFO has Pending Request that generated error,
			 * the RxFIFO need to be empty to activate DMA */
			if (FLEXCAN_GetBuffStatusFlag(base,
					FEATURE_CAN_RXFIFO_FRAME_AVAILABLE) == (uint8_t) 1U) {
				/* Enter CAN in freeze Mode to allow FIFO Clear */
				FLEXCAN_EnterFreezeMode(base);

				FLEXCAN_ClearFIFO(base);
				do { /* Read Offset 0x8C to clear DMA pending request */
					(void) base->RAMn[3];
				} while (FLEXCAN_GetBuffStatusFlag(base,
						FEATURE_CAN_RXFIFO_FRAME_AVAILABLE) == (uint8_t) 1U);

				/* Return CAN to normal Mode */
				FLEXCAN_ExitFreezeMode(base);
			}
			/* Change status of MB to be reconfigured with DMA transfer */
			state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
		}
	}
#endif /* FEATURE_CAN_HAS_DMA_ENABLE */

	/* Start receiving fifo */
	if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state != FLEXCAN_MB_IDLE) {
		return STATUS_BUSY;
	}
	/* Check if RxFIFO feature is enabled */
	if (!FLEXCAN_IsRxFifoEnabled(base)) {
		return STATUS_ERROR;
	}

	state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_RX_BUSY;

	state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].isBlocking = isBlocking;

	/* This will get filled by the interrupt handler */
	state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message = data;

	if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS) {
		/* Enable RX FIFO interrupts*/
		(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING, true);
		(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW,
				true);
		(void) FLEXCAN_SetMsgBuffIntCmd(base,
				FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, true);
	}
#if FEATURE_CAN_HAS_DMA_ENABLE
	if (state->transferType == FLEXCAN_RXFIFO_USING_DMA) {
		status_t edmaStatus;

		edmaStatus = EDMA_DRV_InstallCallback(state->rxFifoDMAChannel,
				FLEXCAN_CompleteRxFifoDataDMA, (void *) ((uint32_t) instance));

		if (edmaStatus != STATUS_SUCCESS) {
			state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
			return STATUS_ERROR;
		}

		edmaStatus = EDMA_DRV_ConfigSingleBlockTransfer(state->rxFifoDMAChannel,
				EDMA_TRANSFER_MEM2MEM, (uint32_t) (base->RAMn),
				(uint32_t) (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message),
				EDMA_TRANSFER_SIZE_4B, 16U);

		if (edmaStatus != STATUS_SUCCESS) {
			state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
			return STATUS_ERROR;
		}

		EDMA_DRV_DisableRequestsOnTransferComplete(state->rxFifoDMAChannel,
				true);

		edmaStat = EDMA_DRV_StartChannel(state->rxFifoDMAChannel);
		if (edmaStat != STATUS_SUCCESS) {
			state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
			return STATUS_ERROR;
		}
	}
#endif

	return STATUS_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_CompleteTransfer
 * Description   : Finish up a transmit by completing the process of sending
 * data and disabling the interrupt.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static void FLEXCAN_CompleteTransfer(uint8_t instance, uint32_t mb_idx) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	/* Disable the transmitter data register empty interrupt */
	(void) FLEXCAN_SetMsgBuffIntCmd(base, mb_idx, false);

	/* Update the information of the module driver state */
	if (state->mbs[mb_idx].isBlocking) {
		(void) OSIF_SemaPost(&state->mbs[mb_idx].mbSema);
	}
	state->mbs[mb_idx].state = FLEXCAN_MB_IDLE;
}

#if FEATURE_CAN_HAS_DMA_ENABLE
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_CompleteRxFifoDataDMA
 * Description   : Finish up a DMA transfer (this is just a wrapper over
 * FLEXCAN_DRV_CompleteRxMessageFifoData).
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static void FLEXCAN_CompleteRxFifoDataDMA(void *parameter,
		edma_chn_status_t status) {
	uint32_t instance = (uint32_t) parameter;

	if (status == EDMA_CHN_ERROR) {
		flexcan_state_t * state = g_flexcanStatePtr[instance];
		state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_DMA_ERROR;
		if (state->callback != NULL) {
			state->callback((uint8_t) instance, FLEXCAN_EVENT_DMA_ERROR,
			FLEXCAN_MB_HANDLE_RXFIFO, state);
		}
	}
	FLEXCAN_CompleteRxMessageFifoData((uint8_t) instance);
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_CompleteRxMessageFifoData
 * Description   : Finish up a receive by completing the process of receiving
 * data and disabling the interrupt.
 * This is not a public API as it is called from other driver functions.
 *
 *END**************************************************************************/
static void FLEXCAN_CompleteRxMessageFifoData(uint8_t instance) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	if (state->transferType == FLEXCAN_RXFIFO_USING_INTERRUPTS) {
		/* Disable RX FIFO interrupts*/
		(void) FLEXCAN_SetMsgBuffIntCmd(base,
				FEATURE_CAN_RXFIFO_FRAME_AVAILABLE, false);
		(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_WARNING,
				false);
		(void) FLEXCAN_SetMsgBuffIntCmd(base, FEATURE_CAN_RXFIFO_OVERFLOW,
				false);
	}
#if FEATURE_CAN_HAS_DMA_ENABLE
	else {
		if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state
				!= FLEXCAN_MB_DMA_ERROR) {
			flexcan_msgbuff_t *fifo_message =
					state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message;
			uint32_t *msgData_32 = (uint32_t *) fifo_message->data;

			(void) EDMA_DRV_StopChannel(state->rxFifoDMAChannel);
			/* Adjust the ID if it is not extended */
			if (((fifo_message->cs) & CAN_CS_IDE_MASK) == 0U) {
				fifo_message->msgId = fifo_message->msgId >> CAN_ID_STD_SHIFT;
			}
			/* Extract the data length */
			fifo_message->dataLen = (uint8_t) ((fifo_message->cs
					& CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
			/* Reverse the endianness */
			FlexcanSwapBytesInWord(msgData_32[0], msgData_32[0]);
			FlexcanSwapBytesInWord(msgData_32[1], msgData_32[1]);
		}
	}
#endif
	/* Clear fifo message*/
	state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mb_message = NULL;

#if FEATURE_CAN_HAS_DMA_ENABLE
	if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state != FLEXCAN_MB_DMA_ERROR) {
		state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
		if ((state->callback != NULL)
				&& (state->transferType == FLEXCAN_RXFIFO_USING_DMA)) {
			state->callback(instance, FLEXCAN_EVENT_DMA_COMPLETE,
			FLEXCAN_MB_HANDLE_RXFIFO, state);
		}
	}
#else
	state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state = FLEXCAN_MB_IDLE;
#endif

	/* Update status for receive by using fifo*/
	if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].isBlocking == true) {
		if (state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].state == FLEXCAN_MB_IDLE) {
			status_t status = OSIF_SemaPost(
					&state->mbs[FLEXCAN_MB_HANDLE_RXFIFO].mbSema);
			DEV_ASSERT(status == STATUS_SUCCESS);
			(void) status;
		}
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_InstallEventCallback
 * Description   : Installs a callback function for the IRQ handler.
 *
 * Implements    : FLEXCAN_DRV_InstallEventCallback_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_InstallEventCallback(uint8_t instance,
		flexcan_callback_t callback, void *callbackParam) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	flexcan_state_t * state = g_flexcanStatePtr[instance];

	state->callback = callback;
	state->callbackParam = callbackParam;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_InstallErrorCallback
 * Description   : Installs an error callback function for the IRQ handler and enables/disables
 *                 error interrupts.
 *
 * Implements    : FLEXCAN_DRV_InstallErrorCallback_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_InstallErrorCallback(uint8_t instance,
		flexcan_error_callback_t callback, void *callbackParam) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];
	flexcan_state_t * state = g_flexcanStatePtr[instance];

	state->error_callback = callback;
	state->errorCallbackParam = callbackParam;
	FLEXCAN_EnterFreezeMode(base);
	if (callback != NULL) {
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, true);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, true);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, true);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, true);
	} else {
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_ERR, false);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_RX_WARNING, false);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_TX_WARNING, false);
		FLEXCAN_SetErrIntCmd(base, FLEXCAN_INT_BUSOFF, false);
	}
	FLEXCAN_ExitFreezeMode(base);
}

#if FEATURE_CAN_HAS_PRETENDED_NETWORKING

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigPN
 * Description   : Configures Pretended Networking settings.
 *
 * Implements    : FLEXCAN_DRV_ConfigPN_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_ConfigPN(uint8_t instance, bool enable,
		const flexcan_pn_config_t *pnConfig) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type * base = g_flexcanBase[instance];

	FLEXCAN_EnterFreezeMode(base);

	if (enable) {
		FLEXCAN_ConfigPN(base, pnConfig);
#if FEATURE_CAN_HAS_SELF_WAKE_UP
		(void)FLEXCAN_SetSelfWakeUp(base, false);
#endif
	}

	FLEXCAN_SetPN(base, enable);

	FLEXCAN_ExitFreezeMode(base);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetWMB
 * Description   : Extracts one of the frames which triggered the wake up event.
 *
 * Implements    : FLEXCAN_DRV_GetWMB_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_GetWMB(uint8_t instance, uint8_t wmbIndex,
		flexcan_msgbuff_t *wmb) {
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);
	DEV_ASSERT(wmb != NULL);
	const CAN_Type *base = g_flexcanBase[instance];
	uint32_t *tmp, wmbData;

	tmp = (uint32_t *) &wmb->data[0];
	wmbData = base->WMB[wmbIndex].WMBn_D03;
	FlexcanSwapBytesInWord(wmbData, *tmp);

	tmp = (uint32_t *) &wmb->data[4];
	wmbData = base->WMB[wmbIndex].WMBn_D47;
	FlexcanSwapBytesInWord(wmbData, *tmp);

	wmb->cs = base->WMB[wmbIndex].WMBn_CS;

	if ((wmb->cs & CAN_CS_IDE_MASK) != 0U) {
		wmb->msgId = base->WMB[wmbIndex].WMBn_ID;
	} else {
		wmb->msgId = base->WMB[wmbIndex].WMBn_ID >> CAN_ID_STD_SHIFT;
	}

	wmb->dataLen = (uint8_t) ((wmb->cs & CAN_CS_DLC_MASK) >> 16);
}

#endif /* FEATURE_CAN_HAS_PRETENDED_NETWORKING */

#if FEATURE_CAN_HAS_SELF_WAKE_UP

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_ConfigSelfWakeUp
 * Description   : Enables/Disables Self Wake Up mode and low pass filter
 * applied to Rx input.
 *
 * Implements    : FLEXCAN_DRV_ConfigSelfWakeUp_Activity
 *END**************************************************************************/
status_t FLEXCAN_DRV_ConfigSelfWakeUp(uint8_t instance, bool enable, bool lowPassFilterEn)
{
	DEV_ASSERT(instance < CAN_INSTANCE_COUNT);

	CAN_Type *base = g_flexcanBase[instance];
	status_t status = STATUS_SUCCESS;

	/* Enable Self Wake Up */
	status = FLEXCAN_SetSelfWakeUp(base, enable);

	if (status == STATUS_SUCCESS)
	{
		FLEXCAN_EnterFreezeMode(base);

		/* Enable Low Pass Filter */
		FLEXCAN_SetWakSrc(base, lowPassFilterEn);

		FLEXCAN_ExitFreezeMode(base);
	}

	return status;
}

#endif /* FEATURE_CAN_HAS_SELF_WAKE_UP */

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_CheckDsample
 * Description   : Check the Sample value
 *
 *END**************************************************************************/
static inline uint32_t FLEXCAN_CheckDsample(uint32_t tmpSample,
		uint32_t samplePoint) {
	if (tmpSample > samplePoint) {
		return (tmpSample - samplePoint);
	}
	return (samplePoint - tmpSample);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_CheckdBitrate
 * Description   : Check the Bitrate value
 *
 *END**************************************************************************/
static inline uint32_t FLEXCAN_CheckdBitrate(uint32_t tmpBitrate,
		uint32_t bitrate) {
	if (tmpBitrate > bitrate) {
		return (tmpBitrate - bitrate);
	}
	return (bitrate - tmpBitrate);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_CheckJumpwidth
 * Description   : Check the JumpWidth value
 *
 *END**************************************************************************/
static inline uint32_t FLEXCAN_CheckJumpwidth(uint32_t pseg1) {
	if (pseg1 < FLEXCAN_RJW_MAX) {
		return pseg1;
	}
	return FLEXCAN_RJW_MAX;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_ProccessTSeg
 * Description   : Calculate Tseg value
 *
 *END**************************************************************************/
static inline void FLEXCAN_ProccessTSeg(uint32_t * tSeg1, uint32_t * tSeg2) {
	/* Adjust time segment 1 and time segment 2 */
	while ((*tSeg1 >= FLEXCAN_TSEG1_MAX) || (*tSeg2 < FLEXCAN_TSEG2_MIN)) {
		*tSeg2 = *tSeg2 + 1U;
		*tSeg1 = *tSeg1 - 1U;
	}
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_ProccessPSeg
 * Description   : Calculate Pseg value
 *
 *END**************************************************************************/
static inline void FLEXCAN_ProccessPSeg(uint32_t * tmpPropseg,
		uint32_t * tmpPseg1) {
	while (*tmpPropseg <= 0U) {
		*tmpPropseg = *tmpPropseg + 1U;
		*tmpPseg1 = *tmpPseg1 - 1U;
	}

	while (*tmpPropseg >= FLEXCAN_PROPSEG_MAX) {
		*tmpPropseg = *tmpPropseg - 1U;
		*tmpPseg1 = *tmpPseg1 + 1U;
	}
}
/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_BitrateToTimeSeg
 * Description   : Converts a bitrate (kbit/s) in time segment values for
 *                 standard CAN frame.
 *
 *END**************************************************************************/
static void FLEXCAN_BitrateToTimeSeg(uint32_t bitrate, uint32_t clkFreq,
		flexcan_time_segment_t *timeSeg) {
	uint32_t dBitrate, tmpBitrate, dBitrateMin, tmpPresdiv, tmpSample,
			dSampleMin, dSample, samplePoint, numTq, pseg1, pseg2, propseg,
			presdiv, tSeg1, tSeg2, tmpPseg1, tmpPseg2, tmpPropseg;

	presdiv = 0U;
	propseg = 0U;
	pseg1 = 0U;
	pseg2 = 0U;

	dSampleMin = 100U;
	dBitrateMin = 1000000U;
	samplePoint = 88U;

	for (tmpPresdiv = 0U; tmpPresdiv < FLEXCAN_PRESDIV_MAX; tmpPresdiv++) {

		/* Compute the number of time quanta in 1 bit time */
		numTq = clkFreq / ((tmpPresdiv + 1U) * bitrate);
		/* Compute the real bitrate resulted */
		tmpBitrate = clkFreq / ((tmpPresdiv + 1U) * numTq);

		/* The number of time quanta in 1 bit time must be lower than the one supported */
		if ((numTq >= FLEXCAN_NUM_TQ_MIN) && (numTq < FLEXCAN_NUM_TQ_MAX)) {
			/* Compute time segments based on the value of the sampling point */
			tSeg1 = (numTq * samplePoint / 100U) - 1U;
			tSeg2 = numTq - 1U - tSeg1;

			/* Adjust time segment 1 and time segment 2 */
			FLEXCAN_ProccessTSeg(&tSeg1, &tSeg2);

			tmpPseg2 = tSeg2 - 1U;

			/* Start from pseg1 = pseg2 and adjust until propseg is valid */
			tmpPseg1 = tmpPseg2;
			tmpPropseg = tSeg1 - tmpPseg1 - 2U;

			FLEXCAN_ProccessPSeg(&tmpPropseg, &tmpPseg1);

			if (((tSeg1 >= FLEXCAN_TSEG1_MAX) || (tSeg2 >= FLEXCAN_TSEG2_MAX)
					|| (tSeg2 < FLEXCAN_TSEG2_MIN)
					|| (tSeg1 < FLEXCAN_TSEG1_MIN))
					|| ((tmpPropseg >= FLEXCAN_PROPSEG_MAX)
							|| (tmpPseg1 >= FLEXCAN_PSEG1_MAX)
							|| (tmpPseg2 < FLEXCAN_PSEG2_MIN)
							|| (tmpPseg2 >= FLEXCAN_PSEG2_MAX))) {
				continue;
			}

			tmpSample = ((tSeg1 + 1U) * 100U) / numTq;
			dSample = FLEXCAN_CheckDsample(tmpSample, samplePoint);
			dBitrate = FLEXCAN_CheckdBitrate(tmpBitrate, bitrate);

			if ((dBitrate < dBitrateMin)
					|| ((dBitrate == dBitrateMin) && (dSample < dSampleMin))) {
				dSampleMin = dSample;
				dBitrateMin = dBitrate;
				pseg1 = tmpPseg1;
				pseg2 = tmpPseg2;
				presdiv = tmpPresdiv;
				propseg = tmpPropseg;

				if ((dBitrate == 0U) && (dSample <= 1U)) {
					break;
				}
			}
		}
	}

	timeSeg->phaseSeg1 = pseg1;
	timeSeg->phaseSeg2 = pseg2;
	timeSeg->preDivider = presdiv;
	timeSeg->propSeg = propseg;
	timeSeg->rJumpwidth = FLEXCAN_CheckJumpwidth(pseg1);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : FLEXCAN_DRV_GetDefaultConfig
 * Description   : Gets the default configuration structure
 *
 * Implements    : FLEXCAN_DRV_GetDefaultConfig_Activity
 *END**************************************************************************/
void FLEXCAN_DRV_GetDefaultConfig(flexcan_user_config_t *config) {
	/* Checks input parameter. */
	DEV_ASSERT(config != NULL);

	uint32_t clkFreq;
	flexcan_time_segment_t timeSeg;

	/* Get the PE clock frequency */
	(void) CLOCK_SYS_GetFreq(FEATURE_CAN_PE_OSC_CLK_NAME, &clkFreq);
	/* Time segments computed for PE bitrate = 500 Kbit/s, sample point = 87.5 */
	FLEXCAN_BitrateToTimeSeg(500000U, clkFreq, &timeSeg);

	/* Maximum number of message buffers */
	config->max_num_mb = 16;
	/* Rx FIFO is disabled */
	config->is_rx_fifo_needed = false;
	/* Number of Rx FIFO ID filters */
	config->num_id_filters = FLEXCAN_RX_FIFO_ID_FILTERS_8;
	/* Normal operation mode */
	config->flexcanMode = FLEXCAN_NORMAL_MODE;
#if FEATURE_CAN_HAS_PE_CLKSRC_SELECT
	/* Protocol engine clock is System Oscillator div 2 */
	config->pe_clock = FLEXCAN_CLK_SOURCE_OSC;
#endif
	/* Time segments for the arbitration phase */
	config->bitrate = timeSeg;
#if FEATURE_CAN_HAS_FD
	/* Payload size */
	config->payload = FLEXCAN_PAYLOAD_SIZE_8;
	/* Flexible data rate is disabled */
	config->fd_enable = false;
	/* Time segments for the data phase of FD frames */
	config->bitrate_cbt = timeSeg;
#endif
	/* Rx FIFO transfer type */
	config->transfer_type = FLEXCAN_RXFIFO_USING_INTERRUPTS;
#if FEATURE_CAN_HAS_DMA_ENABLE
	/* Rx FIFO DMA channel */
	config->rxFifoDMAChannel = 0U;
#endif
}

/*******************************************************************************
 * EOF
 ******************************************************************************/
